package programming.in.scala
import math.{E,Pi}

/**
  * Created by baiwf on 2017/6/4.
  */

abstract class Expr
case class Var(name: String) extends Expr
case class Number(num: Double) extends Expr
case class Unop(operator: String, arg: Expr) extends Expr
case class Binop(operator: String, left: Expr, right: Expr) extends Expr

object ch15CaseClassAndPatternMatch extends App{
  variablePattern(0)

  def simplifyTop(expr: Expr): Expr = expr match {
    case Unop("-",Unop("-",e)) => e
    case Binop("+",e,Number(0)) => e
    case Binop("*",e, Number(1)) => e
    case _ => expr
  }

  //constant patterns
  def describe(x: Any) = x match {
    case 5 => "five"
    case true => "truth"
    case "hello" => "hi"
    case Nil => "the empty list"
    case _ => "something else"
  }

  //other patterns
  def variablePattern(expr: Any): Unit = {
    println(expr match {
      case 0 => "zero"
      case other => "non zero:" + other //has a name for the value
    })

    //作为constant进行匹配
    println(E match {
      case Pi => "strange math"
      case _ => "ok"
    })

    val pi = math.Pi
    println(E match {
      case pi => "pi not a constant:" + pi //小写的认为是pattern variable，大写的才是constant
      case _ => "this is an error statement"
    })

    //如果非要把小写的当作constatnt，应该添加反引号

    //sequence patterns
    expr match {
      case List(0,_,_) => println("found it")
      case _ =>
    }

    expr match {
      case Array(0,_*) => println("found") //_*不限长度匹配，只要前面是0
      case (a,b,c) => println("match:" + a + c) //匹配tuple
      case _ =>
    }

    //给pattern variable限制了类型，相当于是进行类型匹配
    expr match {
      case s: String => s.length
      case m: Map[_,_] => m.size
      case _ => -1
    }
    //上面类型匹配等价于：(这样写麻烦了点)
    if (expr.isInstanceOf[String]) {
      val s = expr.asInstanceOf[String]
      s.length
    }else {

    }
  }

  def isIntIntMap(x: Any) = x match {
    case m: Map[Int,Int] => true //不会匹配到Int,在runtime时会丢失
    case _ => false
  }
  def isStringArray(x: Any) = x match {
    case a: Array[String] => "yes" //array是特例，因为它的类型存储在元素之中
    case _ => "no"
  }

}
